import utils from '@/utils/utils';
import config from '@/config';
import store from '@/store';
import Jsrsasign from 'jsrsasign';
import { encryptByAES, decryptByAES } from './encrypt';

/** 网络请求
 * 封装成promise 抹平fail平台差异， res.data.success不为true自动报错并进入promise catch
 * uni.request的promise模式catch时不方便处理，自己用回调封装成promise
 * 微信环境405等http错误走的success回调，支付宝走的fail
 * @param {string} url
 * @param {Object} options.data 请求数据
 * @param {Boolean} options.noToast 请求失败是否不自动报错
 * @param {Boolean} options.showLoading 是否显示loading
 * @param {Boolean} options.noEncrypt 是否不加密
 * @param {string} encryptKey 加密key
 * @param {Boolean} options.isPrefix 是否前缀
 * @param {Boolean} dataothEncrypt dataoth是否加密
 * @params {*} rest 其他uni.request参数，如data, header, method默认： POST
 * @param {*} [{ data, noToast, showLoading, noEncrypt, encryptKey, isPrefix, dataothEncrypt, ...rest
 */
function request(
  url,
  { data, noToast, showLoading, noEncrypt, encryptKey, isPrefix, dataothEncrypt, ...rest } = {},
  methodType = 'POST'
) {
  showLoading &&
    uni.showLoading({
      title: '加载中',
    });

  const openEncrypt = !noEncrypt && config.isEncrypt;
  const { reversetime, time } = utils.getReverseTime();
  const newEncryptKey = encryptKey || 'zzz' + time;
  let newData = {};

  //加上全局通用
  data = {
    // userCode: store.state.baseInfo.userCode,
    // clAcessToken: store.state.baseInfo.clAccessToken,
    ...(data || {}),
  };

  // 处理历史遗留问题，赋值
  // data.test = data.test;

  if (openEncrypt) {
    if (config.isLog) {
      console.log(`${url}`, data, JSON.stringify(data));
    }
    newData = encodeURIComponent(encryptByAES(JSON.stringify(data), newEncryptKey));
  } else {
    newData = data;
  }

  return new Promise((resolve, reject) => {
    uni.request({
      url: isPrefix ? url : config.getEnvConfig().apiPrefix + url,
      data: newData,
      dataType: 'text',
      header: setRequestHeader(data, reversetime),
      method: methodType, // PUT DELETE GET
      // 微信环境405等http错误也会进此回调
      success: res => {
        if (res.statusCode === 200) {
          if (openEncrypt) {
            res.data = decryptByAES(res.data, newEncryptKey);
          }
          if (dataothEncrypt) {
            let data = JSON.parse(res.data);

            if (!data.loginFlag === 'success') {
              return reject({
                ...res,
                data: JSON.parse(res.data),
              });
            }

            res.data = decryptByAES(data.bizData, config.aesKeyDatath);
          }
          res.data = JSON.parse(res.data);
          if (config.isLog) {
            console.log(`${url}`, res.data);
          }
          resolve(res);
        } else {
          reject(res);
        }
      },
      fail: err => {
        reject(err);
      },
      ...rest,
    });
  }).then(
    res => {
      const data = res.data;
      console.log(777, data);
      showLoading && uni.hideLoading();
      if (data.code === 200) {
        return Promise.resolve(data);
      }
      if (!noToast) {
        utils.toast(
          (data.msg && `${data.msg}${data.code ? '(' + data.code + ')' : ''}`) ||
            data.data ||
            config.serverErrorText
        );
      }
      //服务端返回errMsg, Promise返回reject
      return Promise.reject(data);
    },
    err => {
      showLoading && uni.hideLoading();
      if (!noToast) {
        if (err.statusCode) {
          utils.toast(config.httpErrortText(err.statusCode));
        } else {
          utils.toast(config.networkErrorText);
        }
      }
      return Promise.reject(err);
    }
  );
}

/**签名 */
function getSignTxt(str, pri) {
  if (!str || !pri) {
    return;
  }
  let signTxt;

  const privateKey = `test${pri}`;
  const signature = new Jsrsasign.KJUR.crypto.Signature({
    alg: 'SHA256withRSA',
    prvkeypem: privateKey,
  });
  signature.updateString(str);
  signTxt = Jsrsasign.hextob64(signature.sign());

  return signTxt;
}

/**生成请求头
 * @param {string} param 签名
 * @param {Number} cltime 时间戳
 */
function setRequestHeader(param, cltime) {
  const privateKey = store.state.baseInfo.privateKey || '';
  const token = store.state.baseInfo.token || '';

  //请求参数签名加密
  const sign = getSignTxt(JSON.stringify(param), privateKey);

  let reqHeader = {};

  // #ifdef MP-ALIPAY
  reqHeader['terminal-type'] = 'alimini';
  // #endif

  // #ifdef MP-WEIXIN
  reqHeader['terminal-type'] = 'weixinmini';
  // #endif

  if (token) {
    reqHeader['Authorization'] = `Bearer  ${token}`;
  }

  return {
    cltime, // 反转13位时间戳
    'client-app': config.clientApp,
    ...reqHeader,
    ua: 'clText',
    sign, // 请求签名
  };
}

export default request;
